﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using VNet.VisiSuite.Common;
using VNet.VisiSuite.Common.Resource;
using VNet.VisiSuite.Controls;
using VNet.VisiSuite.Service.Contact.Message;
using VNet.VisiSuite.Service.Contact.Message.Base;
using VNet.VisiSuite.Service.Contact.Message.Item;
using VNet.VisiSuite.VisiCentral.Common;
using VNet.VisiSuite.VisiCentral.Common.Helpers;
using VNet.VisiSuite.VisiCentral.Models;
using VNet.VisiSuite.VisiCentral.Providers;
using VNet.VisiSuite.VisiCentral.Views;

namespace VNet.VisiSuite.VisiCentral.ViewModels
{
    public class AnalysisViewModel : BaseViewModel
    {
        #region Private Variables

        private DateTime _fromDate;
        private DateTime _toDate;

        int _areaId = 13;  // BOGUS HARDCODED

        private List<CheckedName> _shifts;
        private List<CheckedName> _cells;
        private List<CheckedName> _scrapReasonCodes;
        private List<CheckedName> _reasonCodes;
        private List<CheckedName> _products;
        private int _displayScrap = 0;
        private bool _separateOut;
        private int _top_downtime_left = 0;
        private int _top_downtime_left_by = 0;
        private int _top_downtime_right = 0;
        private int _top_downtime_right_by = 1;
        private int _top_downtime_bottom = 0;
        private int _top_downtime_bottom_by = 0;

        #endregion

        #region Public Properties

        public DateTime FromDate
        {
            get { return _fromDate; }
            set
            {
                _fromDate = value;
                OnPropertyChanged("FromDate");
                if (_fromDate > _toDate)
                    ToDate = _fromDate;
            }
        }

        public DateTime ToDate
        {
            get { return _toDate; }
            set
            {
                _toDate = value;
                OnPropertyChanged("ToDate");
            }
        }

        public List<CheckedName> Shifts
        {
            get { return _shifts; }
            set
            {
                _shifts = value;
                OnPropertyChanged("Shifts");
            }
        }

        public int DisplayScrap
        {
            get { return _displayScrap; }
            set
            {
                _displayScrap = value;
                OnPropertyChanged("DisplayScrap");
                PopulateReasonCodes();
            }
        }

        public bool SeparateOut
        {
            get { return _separateOut; }
            set
            {
                _separateOut = value;
                OnPropertyChanged("SeparateOut");
            }
        }

        public List<CheckedName> ReasonCodes
        {
            get {
                if (_displayScrap == 1)
                    return _scrapReasonCodes;
                else
                    return _reasonCodes;
            }
            set
            {
                if (_displayScrap == 1)
                    _scrapReasonCodes = value;
                else
                    _reasonCodes = value;
                OnPropertyChanged("ReasonCodes");
            }
        }

        public List<CheckedName> Cells
        {
            get { return _cells; }
            set {
                _cells = value;
                OnPropertyChanged("Cells");
            }
        }

        public List<CheckedName> Products
        {
            get { return _products; }
            set
            {
                _products = value;
                OnPropertyChanged("Products");
            }
        }

        public int TopDowntimeLeft
        {
            get { return _top_downtime_left; }
            set
            {
                _top_downtime_left = value;
                OnPropertyChanged("TopDowntimeLeft");
            }
        }

        public int TopDowntimeLeftBy
        {
            get { return _top_downtime_left_by; }
            set
            {
                _top_downtime_left_by = value;
                OnPropertyChanged("TopDowntimeLeftBy");
            }
        }

        public int TopDowntimeRight
        {
            get { return _top_downtime_right; }
            set
            {
                _top_downtime_right = value;
                OnPropertyChanged("TopDowntimeRight");
            }
        }

        public int TopDowntimeRightBy
        {
            get { return _top_downtime_right_by; }
            set
            {
                _top_downtime_right_by = value;
                OnPropertyChanged("TopDowntimeRightBy");
            }
        }

        public int TopDowntimeBottom
        {
            get { return _top_downtime_bottom; }
            set
            {
                _top_downtime_bottom = value;
                OnPropertyChanged("TopDowntimeBottom");
            }
        }

        public int TopDowntimeBottomBy
        {
            get { return _top_downtime_bottom_by; }
            set
            {
                _top_downtime_bottom_by = value;
                OnPropertyChanged("TopDowntimeBottomBy");
            }
        }

        #endregion

        public AnalysisViewModel()
        {
            PageTitle = TitleString.AnalysisViewCentralTitle;

            TopLeftButtonIcons = new ObservableCollection<VNetMenuItem> { new VNetMenuItem(null, "Back to Main View", CommonConstants.VNetIcon.AppbarArrowLeft, VNetMenuItemType.WhiteBackgroundTheme, OnMainView) };

            var exportExcelMenuItem = new VNetMenuItem(TitleString.AnalysisView_BottomMenuTitleExcel, TitleString.AnalysisView_BottomMenuTooltipExcel, CommonConstants.VNetIcon.AppbarOfficeExcel, VNetMenuItemType.WhiteBackgroundTheme, OnExportExcel);
            var backMenuItem = new VNetMenuItem(TitleString.AnalysisView_BottomMenuTitleBack, TitleString.AnalysisView_BottomMenuTooltipBack, CommonConstants.VNetIcon.AppbarArrowLeft, VNetMenuItemType.WhiteBackgroundTheme, OnMainView);
            
            var bottomMenuItems = new ObservableCollection<VNetMenuItem>();
            bottomMenuItems.Add(backMenuItem);
            bottomMenuItems.Add(exportExcelMenuItem);
            BottomMenuItems = bottomMenuItems;

            // Set value for from date and to date
            InitializeDateRange();

            // Initialize checkbox lists
            PopulateReasonCodes();
            PopulateCells();
            PopulateShifts();
            PopulateProducts();
        }

        #region Navigation Framwork

        public override void OnNavigate(object obj)
        {
            
        }

        public override void OnLeave()
        {
        }

        public void OnMainView()
        {
            NavigationManager.NavigateTo(new MainView(), null);
        }

        public void OnExportExcel()
        {
            
        }

        #endregion

        #region Initialization

        private void InitializeDateRange()
        {
            var now = DateTime.Now;
            _fromDate = new DateTime(now.Year, now.Month, 1);
            _toDate = now.Date;
        }

        private void PopulateReasonCodes()
        {
            IsBusy = true;
            if (_displayScrap == 1)
                DoAsync(VisiCentralProvider.GetScrapReasonCodes, GetScrapReasonCodesCompleted, _areaId);
            else
                DoAsync(VisiCentralProvider.GetReasonCodes, GetReasonCodesCompleted, _areaId);
        }

        private void PopulateCells()
        {
            IsBusy = true;
            DoAsync(VisiCentralProvider.GetCells, GetCellsCompleted, _areaId);
        }

        private void PopulateShifts()
        {
            IsBusy = true;
            DoAsync(VisiCentralProvider.GetAreaShifts, GetShiftsCompleted, _areaId);
        }

        private void PopulateProducts()
        {
            IsBusy = true;
            DoAsync(VisiCentralProvider.GetProducts, GetProductsCompleted, null);
        }

        #endregion

        #region Callbacks

        private void GetReasonCodesCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<ReasonCodeItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            var reasonCodes = response.Data.ToList();
            reasonCodes = reasonCodes.GroupBy(t => t.Description).Select(x => x.First()).ToList();
            var lstReasonCodes = new List<CheckedName>();
            foreach(var item in reasonCodes)
            {
                var checkedName = new CheckedName(item.Description, item.ReasonCodeId);
                lstReasonCodes.Add(checkedName);
            }
            ReasonCodes = lstReasonCodes;
            IsBusy = false;
        }

        private void GetScrapReasonCodesCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<ReasonCodeItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            var scrapReasonCodes = response.Data.ToList();
            scrapReasonCodes = scrapReasonCodes.GroupBy(t => t.Description).Select(x => x.First()).ToList();
            var lstScrapReasonCodes = new List<CheckedName>();
            foreach (var item in scrapReasonCodes)
            {
                var checkedName = new CheckedName(item.Description, item.ReasonCodeId);
                lstScrapReasonCodes.Add(checkedName);
            }
            ReasonCodes = lstScrapReasonCodes;
            IsBusy = false;

        }

        private void GetCellsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<CellItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            var cells = response.Data.ToList();
            cells = cells.GroupBy(t => t.CellName).Select(x => x.First())
                .OrderBy(t => t.CellName).ToList();
            var lstCells = new List<CheckedName>();
            foreach (var item in cells)
            {
                var checkedName = new CheckedName(item.CellName, item.CellId);
                lstCells.Add(checkedName);
            }
            Cells = lstCells;
            IsBusy = false;
        }

        private void GetShiftsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<AreaShiftItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            var shifts = response.Data.ToList();
            shifts = shifts.GroupBy(t => t.Description).Select(x => x.First())
                .Where(t => !t.Hidden).OrderBy(t => t.Description).ToList();
            var lstShifts = new List<CheckedName>();
            foreach (var item in shifts)
            {
                var checkedName = new CheckedName(item.Description, item.AreaShiftId);
                lstShifts.Add(checkedName);
            }
            Shifts = lstShifts;
            IsBusy = false;
        }

        private void GetProductsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<ProductItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            var products = response.Data.ToList();
            products = products.GroupBy(t => t.Sku).Select(x => x.First())
                .OrderBy(t => t.Sku).ToList();
            var lstProducts = new List<CheckedName>();
            foreach (var item in products)
            {
                var checkedName = new CheckedName(item.Sku, item.ProductId);
                lstProducts.Add(checkedName);
            }
            Products = lstProducts;
            IsBusy = false;
        }

        private void GetAnalysisChartDataCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as AnalysisChartDataResponse;
            IsBusy = false;

            // TODO: Populate the result here
        }

        #endregion

        #region Override Methods

        /// <summary>
        /// Called when [property changed]. Override to fire callback to update charts when any property on the right panel changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected override void OnPropertyChanged(string propertyName)
        {
            base.OnPropertyChanged(propertyName);

            // Call the callback to update the charts on any property on right panel changed
            if (string.Equals(propertyName, "FromDate")
                || string.Equals(propertyName, "ToDate")
                || string.Equals(propertyName, "Shifts")
                || string.Equals(propertyName, "SeparateOut")
                || string.Equals(propertyName, "ReasonCodes")
                || string.Equals(propertyName, "Cells")
                || string.Equals(propertyName, "Products")
                || string.Equals(propertyName, "TopDowntimeLeft")
                || string.Equals(propertyName, "TopDowntimeLeftBy")
                || string.Equals(propertyName, "TopDowntimeRight")
                || string.Equals(propertyName, "TopDowntimeRightBy")
                || string.Equals(propertyName, "TopDowntimeBottom")
                || string.Equals(propertyName, "TopDowntimeBottomBy"))
            {
                // Fire callback to update charts' data
                UpdateChartData();
            }
        }

        #endregion

        #region Update chart's data

        /// <summary>
        /// Updates the chart data with a call back
        /// </summary>
        public void UpdateChartData()
        {
            // Inside this function, need to check for null right panel's properties because when the view model is loaded
            // This function will be fired several times due to properties being set for the first time.
            if (_products != null && _cells != null && _shifts != null && 
                ((_reasonCodes != null && _displayScrap == 0) || (_scrapReasonCodes != null && _displayScrap == 1)))
            {
                IsBusy = true;
                var argument = new AnalysisChartDataArgument()
                {
                    DisplayScrapReasonCode = _displayScrap == 1,
                    FromDate = _fromDate,
                    SeparateOut = _separateOut,
                    ToDate = _toDate,
                    TopDowntimeBottom = _top_downtime_bottom,
                    TopDowntimeBottomBy = _top_downtime_bottom_by,
                    TopDowntimeLeft = _top_downtime_left,
                    TopDowntimeLeftBy = _top_downtime_left_by,
                    TopDowntimeRight = _top_downtime_right,
                    TopDowntimeRightBy = _top_downtime_right_by
                };

                argument.IsAllAreaShiftIdSelected = !_shifts.Any(t => !t.IsChecked);
                argument.IsAllCellIdSelected = !_cells.Any(t => !t.IsChecked);
                argument.IsAllProductIdSelected = !_products.Any(t => !t.IsChecked);
                argument.IsAllReasonCodeIdSelected = (_displayScrap == 0) ? !_reasonCodes.Any(t => !t.IsChecked) 
                    : !_scrapReasonCodes.Any(t => !t.IsChecked);

                argument.ListAreaShiftId = _shifts.Where(t => t.IsChecked).Select(t => t.Id).ToList();
                argument.ListCellId = _cells.Where(t => t.IsChecked).Select(t => t.Id).ToList();
                argument.ListProductId = _products.Where(t => t.IsChecked).Select(t => t.Id).ToList();
                argument.ListReasonCodeId = (_displayScrap == 0) ?
                    _reasonCodes.Where(t => t.IsChecked).Select(t => t.Id).ToList()
                    : _scrapReasonCodes.Where(t => t.IsChecked).Select(t => t.Id).ToList();

                DoAsync(VisiCentralProvider.GetAnalysisChartData, GetAnalysisChartDataCompleted, argument);
                
            }
        }

        #endregion
    }

    public class CheckedName : INotifyPropertyChanged
    {
        private string _name;
        private int _id;
        private bool _is_checked;

        public CheckedName(string name, int id = 0)
        {
            _name = name;
            _id = id;
            _is_checked = true;
        }

        public string Name
        {
            get { return _name; }
        }

        public int Id
        {
            get { return _id; }
        }

        public bool IsChecked
        {
            get { return _is_checked; }
            set
            {
                _is_checked = value;
                NotifyPropertyChanged("IsChecked");
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Raises this object's PropertyChanged event.
        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }

        public void NotifyPropertyChanged(string property_name)
        {
            var e = new PropertyChangedEventArgs(property_name);
            OnPropertyChanged(e);
        }

        #endregion

    }

}
